package com.zatech.cgnci.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zatech.cgnci.project.base.context.UserContext;
import com.zatech.cgnci.project.base.enums.*;
import com.zatech.cgnci.project.base.exception.GlobalException;
import com.zatech.cgnci.project.base.utils.BeanUtils;
import com.zatech.cgnci.project.base.utils.ConvertUtils;
import com.zatech.cgnci.project.base.utils.DateUtils;
import com.zatech.cgnci.project.base.utils.ThreadPoolUtils;
import com.zatech.cgnci.project.dto.*;
import com.zatech.cgnci.project.entity.*;
import com.zatech.cgnci.project.mapper.*;
import com.zatech.cgnci.project.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zatech.cgnci.project.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 临分摊赔账单信息 服务实现类
 * </p>
 *
 * @author Generator
 * @since 2024-12-30
 */
@Service
public class CgnciProportionalLiabilityInvoiceServiceImpl extends ServiceImpl<CgnciProportionalLiabilityInvoiceMapper, CgnciProportionalLiabilityInvoiceDO> implements CgnciProportionalLiabilityInvoiceService {
    @Autowired
    private CgnciProportionalLiabilityDetailsMapper detailsMapper;
    @Autowired
    private CgnciReceiptPaymentBillsMapper billsMapper;
    @Autowired
    private CgnciBusinessInsuranceMapper insuranceMapper;
    @Resource
    private CgnciClaimSettlementService claimSettlementService;
    @Resource
    private CgnciClaimCaseMapper claimCaseMapper;
    @Resource
    private CgnciRiskService riskService;
    @Resource
    private CgnciDirectInsuranceService directInsuranceService;

    @Override
    public IPage<ProportionalLiabilityInvoiceVO> pageQuery(ProportionalLiabilityInvoiceDTO queryDTO) {
        return this.baseMapper.pageBusinessInsurance(queryDTO.toPage(), queryDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertClaimSettlement(String caseNo, String settlementType) {
//        ThreadPoolUtils.executor(() -> {
        CgnciClaimCaseDO cgnciClaimCaseDO = claimCaseMapper.selectOne(new LambdaQueryWrapper<CgnciClaimCaseDO>()
                .eq(CgnciClaimCaseDO::getCaseNo, caseNo));
        List<CgnciClaimSettlementVO> settlementVOS = claimSettlementService.queryClaimSettlementByCaseNo(caseNo);
        //只查分出
        CgnciBusinessInsuranceDO insuranceDO = insuranceMapper.selectOne(new LambdaQueryWrapper<CgnciBusinessInsuranceDO>()
                .eq(CgnciBusinessInsuranceDO::getBusinessNo, cgnciClaimCaseDO.getPolicyNo())
                .eq(CgnciBusinessInsuranceDO::getBusinessType, "1")
                .eq(CgnciBusinessInsuranceDO::getStatus, "3")
                .eq(CgnciBusinessInsuranceDO::getIsMirror, "0"));
        if (Objects.isNull(insuranceDO)) {
            return;
        }
        // 查询直保信息
        CgnciDirectInsuranceVO directInsuranceVO = directInsuranceService.getDirectInsuranceByBusinessId(insuranceDO.getInsuranceId());

        settlementVOS.forEach(settlementVO -> {
            if (settlementVO.getSettlementType().equals(settlementType)) {
                insertSettlement(settlementVO, cgnciClaimCaseDO, insuranceDO, directInsuranceVO);
            }
        });
//        });
    }

    @Transactional(rollbackFor = Exception.class)
    public void insertSettlement(CgnciClaimSettlementVO settlementVO, CgnciClaimCaseDO cgnciClaimCaseDO, CgnciBusinessInsuranceDO insuranceDO,
                                 CgnciDirectInsuranceVO directInsuranceVO) {
        settlementVO.getSpreadBackSettlementList().forEach(spr -> {
            // 险种分组
            Map<String, List<CgnciClaimSettlementVO.DetailVO>> riskTypeMap
                    = spr.getDetails().stream().collect(Collectors.groupingBy(CgnciClaimSettlementVO.DetailVO::getRiskType));
            riskTypeMap.forEach((riskType, details) -> {
                ProportionalLiabilityInvoiceAddDTO premiumBillAddDTO = new ProportionalLiabilityInvoiceAddDTO();
                premiumBillAddDTO.setPolicyNumber(cgnciClaimCaseDO.getPolicyNo());
                premiumBillAddDTO.setContractType("2");
                premiumBillAddDTO.setCedingCompany("CGN Captive Insurance Limited");
                premiumBillAddDTO.setReceiver(spr.getReinsurerName());
                premiumBillAddDTO.setProjectName(insuranceDO.getProjectName());
                premiumBillAddDTO.setReinsuranceBroker(spr.getReinsurerName());
                premiumBillAddDTO.setClaimName(cgnciClaimCaseDO.getCaseName());
                premiumBillAddDTO.setClaimId(cgnciClaimCaseDO.getCaseNo());
                premiumBillAddDTO.setPolicyTerm(insuranceDO.getInsuranceDays().toString());
                premiumBillAddDTO.setPolicyTermDesc("from      " + DateUtils.dateToString(insuranceDO.getStartDate(), "yyyy-MM-dd") + "      to      " + DateUtils.dateToString(insuranceDO.getEndDate(), "yyyy-MM-dd"));
                premiumBillAddDTO.setPolicyYear(insuranceDO.getBusinessYear());
                premiumBillAddDTO.setPolicyType(riskType);
                // 获取险种中文名称
                premiumBillAddDTO.setPolicyTypeName(riskService.getOne(new LambdaQueryWrapper<CgnciRiskDO>().eq(CgnciRiskDO::getRiskSubTypeCode, riskType)).getRiskSubType());
                //premiumBillAddDTO.setCurrency(insuranceDO.getCurrency());
                premiumBillAddDTO.setCurrency(cgnciClaimCaseDO.getSettlementCurrency());
                premiumBillAddDTO.setLossDate(cgnciClaimCaseDO.getAccidentDate());
                premiumBillAddDTO.setCauseOfLoss(cgnciClaimCaseDO.getAccidentReason());
                //premiumBillAddDTO.setFxRate(insuranceDO.getExchangeRate());
                premiumBillAddDTO.setFxRate(spr.getReinsurerRate());
                premiumBillAddDTO.setBillRecipient(spr.getReinsurerName());
//                        premiumBillAddDTO.setBillingCycle();
//                        premiumBillAddDTO.setPostingDate();
//                        premiumBillAddDTO.setDueDate();待确认
                premiumBillAddDTO.setDirection(DirectionEnum.COLLECTION.getCode());
                List<ContractBillDetailsAddDTO> detailsAddDTOS = new ArrayList<>();
                ContractBillDetailsAddDTO addDTO = new ContractBillDetailsAddDTO();
                //addDTO.setFeeType("4");
                addDTO.setPaymentType(DirectionEnum.COLLECTION.getCode());
                addDTO.setAmount(BeanUtils.sumBigDecimalProperty(details, CgnciClaimSettlementVO.DetailVO::getSettlementAmount));
                detailsAddDTOS.add(addDTO);
                /*ContractBillDetailsAddDTO addDTO1 = new ContractBillDetailsAddDTO();
                addDTO1.setFeeType("6");
                addDTO1.setPaymentType(DirectionEnum.COLLECTION.getCode());
                addDTO1.setAmount(new BigDecimal(0));
                detailsAddDTOS.add(addDTO1);*/
                premiumBillAddDTO.setCollectAmount(BeanUtils.sumBigDecimalProperty(details, CgnciClaimSettlementVO.DetailVO::getSettlementAmount));
                premiumBillAddDTO.setDetailsAddDTOS(detailsAddDTOS);
                premiumBillAddDTO.setStatDate(insuranceDO.getStartDate());
                premiumBillAddDTO.setEndDate(insuranceDO.getEndDate());
                premiumBillAddDTO.setTotalAmount(settlementVO.getTotalAmount());
                premiumBillAddDTO.setCededRatio(BeanUtils.sumBigDecimalProperty(details, CgnciClaimSettlementVO.DetailVO::getCededRatio));
                premiumBillAddDTO.setRemarks(settlementVO.getRemarks());
                premiumBillAddDTO.setInsuredInsurer(directInsuranceVO.getInsuredInsurer());
                addContractInvoice(premiumBillAddDTO);
            });
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addContractInvoice(ProportionalLiabilityInvoiceAddDTO addDTO) {
        CgnciProportionalLiabilityInvoiceDO invoiceDO = ConvertUtils.convert(addDTO, CgnciProportionalLiabilityInvoiceDO.class);
        CgnciReceiptPaymentBillsDO paymentBillsDO = ConvertUtils.convert(invoiceDO, CgnciReceiptPaymentBillsDO.class);
        paymentBillsDO.setCreateUser(addDTO.getUser());
        paymentBillsDO.setCreateTime(new Date());
        paymentBillsDO.setAmount(invoiceDO.getCollectAmount());
        paymentBillsDO.setId(null);
        paymentBillsDO.setBillType(BillTypeEnum.PROPORTIONAL_LIABILITY_INVOICE.getCode());
        if (Objects.isNull(invoiceDO.getId())) {
            invoiceDO.setStatus(BillStatusEnum.UNSETTLED.getCode());
            StringBuilder invoiceNumber = new StringBuilder();
            if (addDTO.getDirection().equals("1")) {
                invoiceNumber.append("SK");
            } else if (addDTO.getDirection().equals("2")) {
                invoiceNumber.append("FK");
            }
            invoiceNumber.append(DateUtils.dateElaborate());
            // 获取当前日期的开始时间和结束时间
            LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
            LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
            int count = this.baseMapper.selectCount(
                    new LambdaQueryWrapper<CgnciProportionalLiabilityInvoiceDO>()
                            .between(CgnciProportionalLiabilityInvoiceDO::getCreateTime,
                                    Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()),
                                    Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()))
            );
            invoiceNumber.append(String.format("%04d", count));
            invoiceDO.setInvoiceNumber(invoiceNumber.toString());
            //插入收付费账单表
            paymentBillsDO.setInvoiceNumber(invoiceNumber.toString());
            paymentBillsDO.setStatus(BillStatusEnum.UNSETTLED.getCode());
            billsMapper.insert(paymentBillsDO);
        } else {
            Integer count = billsMapper.selectCount(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                    .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, addDTO.getInvoiceNumber())
                    .eq(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.UNSETTLED.getCode()));
            if (count == 0) {
                throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "收付费平台已关联，不允许编辑");
            }
            //更新收付费账单表
            billsMapper.update(paymentBillsDO, new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>().eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceDO.getInvoiceNumber()));
        }
        detailsMapper.delete(new LambdaQueryWrapper<CgnciProportionalLiabilityDetailsDO>().eq(CgnciProportionalLiabilityDetailsDO::getInvoiceNumber, invoiceDO.getInvoiceNumber()));
        for (ContractBillDetailsAddDTO detailsAddDTO : addDTO.getDetailsAddDTOS()) {
            //账单明细
            CgnciProportionalLiabilityDetailsDO cgnciContractBillDetailsDO = CgnciProportionalLiabilityDetailsDO.builder()
                    .invoiceNumber(invoiceDO.getInvoiceNumber())
                    .feeType(detailsAddDTO.getFeeType())
                    .paymentType(detailsAddDTO.getPaymentType())
                    .amount(detailsAddDTO.getAmount())
                    .createUser(addDTO.getUser())
                    .createTime(new Date())
                    .build();
            detailsMapper.insert(cgnciContractBillDetailsDO);
        }
        invoiceDO.setPolicyTypeName(riskService.getOne(new LambdaQueryWrapper<CgnciRiskDO>().eq(CgnciRiskDO::getRiskSubTypeCode, invoiceDO.getPolicyType())).getRiskSubType());
        invoiceDO.setCreateUser(addDTO.getUser());
        this.saveOrUpdate(invoiceDO);
    }

    @Override
    public LiabilityInvoiceDetailsVO getDetails(Long id) {
        CgnciProportionalLiabilityInvoiceDO invoiceDO = this.baseMapper.selectById(id);
        LiabilityInvoiceDetailsVO detailsVO = ConvertUtils.convert(invoiceDO, LiabilityInvoiceDetailsVO.class);
        List<CgnciProportionalLiabilityDetailsDO> detailsDOList = detailsMapper.selectList(new LambdaUpdateWrapper<CgnciProportionalLiabilityDetailsDO>()
                .eq(CgnciProportionalLiabilityDetailsDO::getInvoiceNumber, invoiceDO.getInvoiceNumber()));
        List<ContractBillDetailsAddDTO> detailsAddDTOS = new ArrayList<>();
        for (CgnciProportionalLiabilityDetailsDO detailsDO : detailsDOList) {
            ContractBillDetailsAddDTO detailsAddDTO = new ContractBillDetailsAddDTO();
            detailsAddDTO.setAmount(detailsDO.getAmount());
            detailsAddDTO.setPaymentType(detailsDO.getPaymentType());
            detailsAddDTO.setFeeType(detailsDO.getFeeType());
            detailsAddDTOS.add(detailsAddDTO);
        }
        detailsVO.setDetailsAddDTOS(detailsAddDTOS);
        return detailsVO;
    }

    @Override
    public void updateUpm(ContractInvoiceUpmUpDTO updateDTO) {
        //合约账单
        CgnciProportionalLiabilityInvoiceDO cgnciContractInvoiceDO = CgnciProportionalLiabilityInvoiceDO.builder()
                .id(updateDTO.getId())
                .upmNumber(updateDTO.getUpmNumber())
                .postingDate(updateDTO.getPostingDate())
                .updateUser(updateDTO.getUpdateUser())
                .updateTime(new Date())
                .build();
        this.baseMapper.updateById(cgnciContractInvoiceDO);
    }

    @Override
    public void delete(Long id, String invoiceNumber) {
        Integer count = billsMapper.selectCount(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceNumber)
                .eq(CgnciReceiptPaymentBillsDO::getStatus, BillStatusEnum.UNSETTLED.getCode()));
        if (count == 0) {
            throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "收付费已关联，不允许删除");
        }
        this.baseMapper.deleteById(id);
        // 构建 LambdaQueryWrapper 并设置删除条件
        LambdaQueryWrapper<CgnciProportionalLiabilityDetailsDO> wrapper = new LambdaQueryWrapper<CgnciProportionalLiabilityDetailsDO>()
                .eq(CgnciProportionalLiabilityDetailsDO::getInvoiceNumber, invoiceNumber);
        detailsMapper.delete(wrapper);

        //删除收付费管理数据
        billsMapper.delete(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber, invoiceNumber));
    }
}
